import tkinter as tk
from tkinter import ttk, messagebox
import os
import sys

# 添加项目根目录到路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from main import get_versions, get_active_profile
from gui.encode_panel import EncodePanel
from gui.decode_panel import DecodePanel
from gui.auto_tasks import AutoTaskManager


class MainWindow:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("808协议数据帧生成与解析工具")
        self.root.geometry("1400x800")
        
        # 设置窗口图标（如果有的话）
        try:
            self.root.iconbitmap("icon.ico")
        except:
            pass
        
        # 初始化版本管理
        self.versions = get_versions()
        self.active_profile = get_active_profile()
        
        self.setup_ui()
        # 自动任务管理
        self.auto_tasks = AutoTaskManager()
        self._tick_running = False
        self._start_tick()
        
    def setup_ui(self):
        """设置用户界面"""
        # 创建主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 移除标题

        # 创建两列分割面板
        paned_window = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
        paned_window.pack(fill=tk.BOTH, expand=True)

        # 左列：TCP（上：连接；下：日志）
        left_frame = ttk.Frame(paned_window)
        paned_window.add(left_frame, weight=1)

        # 左列内部上下分割
        inner = ttk.PanedWindow(left_frame, orient=tk.VERTICAL)
        inner.pack(fill=tk.BOTH, expand=True)

        from network.tcp_client import TcpClient
        from gui.tcp_panel import TcpPanel
        from gui.tcp_logs import TcpLogs

        self.tcp_client = TcpClient()
        self.tcp_panel = TcpPanel(inner, self.tcp_client)

        # 发送/接收日志，回调：重发 与 送至解码
        def resend_cb(b: bytes):
            try:
                self.tcp_client.send(b)
            except Exception as e:
                messagebox.showerror('发送失败', str(e))

        def to_decode_cb(b: bytes):
            # 放入右侧解码面板并自动解析
            try:
                from protocol.codec import to_hex
                self.decode_panel.input_text.delete('1.0', tk.END)
                self.decode_panel.input_text.insert('1.0', to_hex(b))
                self.decode_panel.parse_frame()
            except Exception as e:
                # 清空输出结果
                self.decode_panel.json_text.delete('1.0', tk.END)
                self.decode_panel.last_parsed_data = None
                messagebox.showerror('送至解码面板失败', f'无法将数据送至解码面板: {str(e)}')

        self.tcp_logs = TcpLogs(inner, resend_cb, to_decode_cb)

        inner.add(self.tcp_panel.frame, weight=0)
        inner.add(self.tcp_logs.frame, weight=1)

        # 右侧：创建Tab页（包含编码和解码面板）
        right_frame = ttk.Frame(paned_window)
        paned_window.add(right_frame, weight=2)

        # 创建Notebook（Tab容器）
        notebook = ttk.Notebook(right_frame)
        notebook.pack(fill=tk.BOTH, expand=True)

        # Tab 1: 数据帧生成（编码面板）
        self.encode_panel = EncodePanel(notebook, self.versions, self.active_profile)
        notebook.add(self.encode_panel.frame, text="数据帧生成")
        # 注入TCP引用到编码面板
        try:
            self.encode_panel.set_tcp_refs(self.tcp_client, self.tcp_logs)
            self.encode_panel.set_task_hooks(self._start_auto_task, self._stop_auto_task, self._is_task_running)
        except Exception:
            pass

        # Tab 2: 数据帧解析（解码面板）
        self.decode_panel = DecodePanel(notebook, self.versions, self.active_profile)
        notebook.add(self.decode_panel.frame, text="数据帧解析")

        # 设置两列分割，并设置最小宽度（基于容器真实宽度，避免面板消失）
        # 设置最小宽度（ttk.PanedWindow 使用 pane 子命令）
        try:
            paned_window.pane(left_frame, minsize=200)
            paned_window.pane(right_frame, minsize=600)
        except Exception:
            pass

        def _set_equal_sashes():
            paned_window.update_idletasks()
            w = paned_window.winfo_width()
            if w <= 10 or len(paned_window.panes()) < 2:
                # 等容器稳定后再设置
                self.root.after(100, _set_equal_sashes)
                return
            # 左边约占1/3，右边约占2/3
            left_width = max(200, int(w / 3))
            try:
                paned_window.sashpos(0, left_width)
            except Exception:
                pass

        _set_equal_sashes()
        # 当窗口尺寸变化时，保持比例
        paned_window.bind('<Configure>', lambda e: _set_equal_sashes())

        # 向根窗口挂载引用，便于子组件访问
        self.root.tcp_client_ref = self.tcp_client
        self.root.tcp_logs_ref = self.tcp_logs

        # 包装 TCP 连接/断开回调：连接后禁用版本与SIM并自动发送0x0102；断开后恢复
        prev_on_connected = getattr(self.tcp_client, 'on_connected', None)
        prev_on_disconnected = getattr(self.tcp_client, 'on_disconnected', None)

        def _after_connected():
            # 先调用原有回调以更新状态栏
            try:
                if callable(prev_on_connected):
                    prev_on_connected()
            except Exception:
                pass
            # 禁用协议版本与SIM输入（JSON及按钮禁用交由任务管理器驱动）
            try:
                self.encode_panel.version_combo.config(state=tk.DISABLED)
                self.encode_panel.sim_entry.config(state=tk.DISABLED)
            except Exception:
                pass
            # 连接后自动发送一次 0x0102（SIM取界面值）
            try:
                from main import encode_message
                sim_number = (self.encode_panel.sim_var.get() or '').strip() or '13800138000'
                active_profile = self.encode_panel.active_profile
                frame_bytes = encode_message('0x0102', active_profile, None, sim_number, sim=sim_number)
                # 发送
                self.tcp_client.send(frame_bytes)
                # 记录发送日志（指令ID-名称）
                self.tcp_logs.append_send('0x0102-终端鉴权', frame_bytes)
            except Exception as e:
                messagebox.showerror('自动发送失败', f'连接成功后自动发送0x0102失败: {str(e)}')

        def _after_disconnected():
            # 先调用原有回调以更新状态栏
            try:
                if callable(prev_on_disconnected):
                    prev_on_disconnected()
            except Exception:
                pass
            # 恢复协议版本与SIM输入（JSON及按钮的恢复由 _stop_all_tasks 统一处理）
            try:
                self.encode_panel.version_combo.config(state='readonly')
                self.encode_panel.sim_entry.config(state=tk.NORMAL)
            except Exception:
                pass
            # 断开后停止所有定时任务并恢复编辑状态
            try:
                self._stop_all_tasks()
            except Exception:
                pass

        # 覆盖客户端回调为包装后的函数
        self.tcp_client.on_connected = _after_connected
        self.tcp_client.on_disconnected = _after_disconnected

        # 底部状态栏（自动任务状态）
        status_frame = ttk.Frame(self.root)
        status_frame.pack(fill=tk.X, side=tk.BOTTOM)
        self.status_var = tk.StringVar(value='')
        ttk.Label(status_frame, textvariable=self.status_var, anchor='w').pack(fill=tk.X)

        # 绑定接收回调：写入接收日志并尝试解析指令ID
        def _on_recv(data: bytes):
            # 直接从数据帧中提取指令ID，不依赖完整解析
            cmd_display = "未知"
            try:
                from protocol.codec import unescape_bytes
                from protocol.frames.registry import _FRAME_INFO
                
                # 检查帧边界
                if len(data) >= 4 and data[0] == 0x7e and data[-1] == 0x7e:
                    inner = data[1:-1]
                    raw = unescape_bytes(inner)
                    if len(raw) >= 2:
                        # 直接读取指令ID
                        msg_id = int.from_bytes(raw[0:2], 'big')
                        cmd_id = f"0x{msg_id:04x}"
                        
                        # 检查是否为已知指令，获取指令名称
                        if msg_id in _FRAME_INFO:
                            cmd_name = _FRAME_INFO[msg_id]['name']
                            cmd_display = f"{cmd_id}-{cmd_name}"
                        else:
                            # 未知指令
                            cmd_display = f"{cmd_id}-未知"
            except Exception:
                # 解析失败，标记为未知
                cmd_display = "未知"
            self.tcp_logs.append_recv(cmd_display, data)
        self.tcp_client.on_received = _on_recv
        
    def run(self):
        """运行主窗口"""
        self.root.mainloop()

    # ===== 自动发送任务管理 =====
    def _start_auto_task(self, cmd_id: str, display: str, freq_sec: int, json_disable_setter, generate_and_send_func) -> bool:
        now = self._now_ms()
        ok = self.auto_tasks.start_task(
            cmd_id, display, freq_sec,
            json_disable_setter, generate_and_send_func,
            now_ms=now,
            connected=getattr(self.tcp_client, 'connected', False),
            error_cb=lambda m: messagebox.showwarning('提示', m)
        )
        self._refresh_status_line()
        return ok

    def _stop_auto_task(self, cmd_id: str):
        self.auto_tasks.stop_task(cmd_id)
        self._refresh_status_line()

    def _is_task_running(self, cmd_id: str) -> bool:
        return self.auto_tasks.is_running(cmd_id)

    def _stop_all_tasks(self):
        self.auto_tasks.stop_all()
        # 清空所有指令状态缓存
        self.encode_panel._cmd_states.clear()
        # 重置自动发送按钮文本为初始状态
        self.encode_panel.auto_btn.config(text='自动发送')
        # 恢复频次输入框状态
        self.encode_panel.auto_freq_entry.config(state=tk.NORMAL)
        # 恢复JSON编辑器可编辑状态
        self.encode_panel._set_json_editable(True)
        # 恢复生成/发送按钮状态
        try:
            self.encode_panel.btn_generate.config(state=tk.NORMAL)
            self.encode_panel.btn_send.config(state=tk.NORMAL)
        except Exception:
            pass
        self._refresh_status_line()

    def _now_ms(self) -> int:
        import time
        return int(time.time() * 1000)

    def _tick(self):
        # 每秒检查
        now = self._now_ms()
        self.auto_tasks.tick(now_ms=now, connected=getattr(self.tcp_client, 'connected', False),
                             error_cb=lambda m: messagebox.showerror('自动发送失败', m))
        self._refresh_status_line()
        self.root.after(1000, self._tick)

    def _start_tick(self):
        if not self._tick_running:
            self._tick_running = True
            self.root.after(1000, self._tick)

    def _refresh_status_line(self):
        if hasattr(self, 'status_var'):
            self.status_var.set(self.auto_tasks.summary_line())


if __name__ == "__main__":
    app = MainWindow()
    app.run()
